﻿namespace TestTool.GUI.Controllers
{
    using System;
    using System.Globalization;
    using System.Threading;
    using TestTool.GUI.Data;
    using TestTool.GUI.Enums;
    using TestTool.GUI.Utils;
    using TestTool.GUI.Views;
    using TestTool.Proxies.Onvif;
    using TestTool.Tests.Common.CommonUtils;

    internal class MediaController : Controller<IMediaView>
    {
        private ManagementServiceProvider _deviceClient;
        private bool _deviceClientWorking;
        private MediaServiceProvider _mediaClient;
        private bool _mediaClientWorking;

        public MediaController(IMediaView view) : base(view)
        {
        }

        public void GetAudioEncoderConfigOptions(string encoder)
        {
            string mediaAddress = base.View.MediaAddress;
            this._mediaClientWorking = true;
            this.InitializeMediaClient(mediaAddress);
            this._mediaClient.GetAudioEncoderConfigOptions(encoder);
        }

        public void GetAudioEncoderConfigurations()
        {
            string mediaAddress = base.View.MediaAddress;
            this._mediaClientWorking = true;
            this.InitializeMediaClient(mediaAddress);
            this._mediaClient.GetAudioEncoderConfigurations();
        }

        public void GetAudioSourceConfigurations()
        {
            string mediaAddress = base.View.MediaAddress;
            this._mediaClientWorking = true;
            this.InitializeMediaClient(mediaAddress);
            this._mediaClient.GetAudioSourceConfigurations();
        }

        public void GetMediaAddress()
        {
            DiscoveredDevices discoveredDevices = ContextController.GetDiscoveredDevices();
            this._deviceClientWorking = true;
            string address = (discoveredDevices != null) ? discoveredDevices.ServiceAddress : string.Empty;
            this.InitializeDeviceClient(address);
            bool capabilitiesStyle = ContextController.GetDebugInfo().CapabilitiesExchange == CapabilitiesExchangeStyle.GetCapabilities;
            this._deviceClient.GetServiceAddresses(capabilitiesStyle, new CapabilityCategory[] { CapabilityCategory.Media });
        }

        public void GetMediaProfiles()
        {
            string mediaAddress = base.View.MediaAddress;
            this._mediaClientWorking = true;
            this.InitializeMediaClient(mediaAddress);
            this._mediaClient.GetProfiles();
        }

        public void GetMediaUri(TestTool.Proxies.Onvif.Profile profile, TransportProtocol protocol)
        {
            string mediaAddress = base.View.MediaAddress;
            this._mediaClientWorking = true;
            this.InitializeMediaClient(mediaAddress);
            this._mediaClient.GetMediaUri(profile, protocol);
        }

        public void GetMediaUri(TestTool.Proxies.Onvif.Profile profile, VideoSourceConfiguration videoSourceConfig, VideoEncoderConfiguration videoEncoderConfig, AudioSourceConfiguration audioSourceConfig, AudioEncoderConfiguration audioEncoderConfig, TransportProtocol protocol)
        {
            if ((videoEncoderConfig == null) || (videoSourceConfig == null))
            {
                throw new ArgumentNullException();
            }
            string mediaAddress = base.View.MediaAddress;
            this._mediaClientWorking = true;
            this.InitializeMediaClient(mediaAddress);
            this._mediaClient.GetMediaUri(profile, videoSourceConfig, videoEncoderConfig, audioSourceConfig, audioEncoderConfig, protocol);
        }

        public void GetVideoEncoderConfigOptions(string encoder)
        {
            string mediaAddress = base.View.MediaAddress;
            this._mediaClientWorking = true;
            this.InitializeMediaClient(mediaAddress);
            this._mediaClient.GetVideoEncoderConfigOptions(encoder);
        }

        public void GetVideoEncoderConfigurations()
        {
            string mediaAddress = base.View.MediaAddress;
            this._mediaClientWorking = true;
            this.InitializeMediaClient(mediaAddress);
            this._mediaClient.GetVideoEncoderConfigurations();
        }

        public void GetVideoSourceConfigurations()
        {
            string mediaAddress = base.View.MediaAddress;
            this._mediaClientWorking = true;
            this.InitializeMediaClient(mediaAddress);
            this._mediaClient.GetVideoSourceConfigurations();
        }

        private void InitializeDeviceClient(string address)
        {
            DeviceEnvironment deviceEnvironment = ContextController.GetDeviceEnvironment();
            this._deviceClient = new ManagementServiceProvider(address, deviceEnvironment.Timeouts.Message);
            this._deviceClient.ExceptionThrown += new Action<string, Exception>(this.OnExceptionThrown);
            this._deviceClient.OperationCompleted += new Action(this.OnOperationCompleted);
            this._deviceClient.OperationStarted += new Action(this.OnOperationStarted);
            this._deviceClient.Timeout = deviceEnvironment.Timeouts.Message;
            this._deviceClient.ResponseReceived += new Action<string>(this.OnResponseReceived);
            this._deviceClient.OnServicesInfoReceived += new ManagementServiceProvider.ServicesInfoReceived(this.OnServicesInfoReceived);
            this._deviceClient.Security = ContextController.GetDebugInfo().Security;
        }

        private void InitializeMediaClient(string address)
        {
            DeviceEnvironment deviceEnvironment = ContextController.GetDeviceEnvironment();
            this._mediaClient = new MediaServiceProvider(address, deviceEnvironment.Timeouts.Message);
            this._mediaClient.ExceptionThrown += new Action<string, Exception>(this.OnExceptionThrown);
            this._mediaClient.OperationCompleted += new Action(this.OnOperationCompleted);
            this._mediaClient.OperationStarted += new Action(this.OnOperationStarted);
            this._mediaClient.OnProfilesReceived += new MediaServiceProvider.ProfilesReceived(this.OnProfilesReceived);
            this._mediaClient.OnVideoSourceConfigurationsReceived += new MediaServiceProvider.VideoSourceConfigurationsReceived(this.OnSourceConfigsReceived);
            this._mediaClient.OnVideoEncoderConfigurationReceived += new MediaServiceProvider.VideoEncoderConfigurationReceived(this.OnVideoEncoderConfigsReceived);
            this._mediaClient.OnVideoEncoderConfigOptionsReceived += new MediaServiceProvider.VideoEncoderConfigOptionsReceived(this.OnVideoEncoderConfigOptionsReceived);
            this._mediaClient.OnAudioSourceConfigurationsReceived += new MediaServiceProvider.AudioSourceConfigurationsReceived(this.OnAudioSourceConfigsReceived);
            this._mediaClient.OnAudioEncoderConfigurationReceived += new MediaServiceProvider.AudioEncoderConfigurationReceived(this.OnAudioEncoderConfigsReceived);
            this._mediaClient.OnAudioEncoderConfigOptionsReceived += new MediaServiceProvider.AudioEncoderConfigOptionsReceived(this.OnAudioEncoderConfigOptionsReceived);
            this._mediaClient.OnMediaUriReceived += new MediaServiceProvider.MediaUriReceived(this.OnMediaUriReceived);
            this._mediaClient.Timeout = deviceEnvironment.Timeouts.Message;
            this._mediaClient.ResponseReceived += new Action<string>(this.OnResponseReceived);
            this._mediaClient.Security = ContextController.GetDebugInfo().Security;
        }

        public override void LoadSavedContext(SavedContext context)
        {
            if (context.MediaInfo != null)
            {
                base.View.MediaAddress = context.MediaInfo.ServiceAddress;
            }
        }

        protected void OnAudioEncoderConfigOptionsReceived(AudioEncoderConfigurationOptions options)
        {
            base.View.SetAudioEncoderConfigOptions(options);
        }

        protected void OnAudioEncoderConfigsReceived(AudioEncoderConfiguration[] configs)
        {
            base.View.SetAudioEncoderConfigs(configs);
        }

        protected void OnAudioSourceConfigsReceived(AudioSourceConfiguration[] configs)
        {
            base.View.SetAudioSourceConfigs(configs);
        }

        private void OnExceptionThrown(string stage, Exception exc)
        {
            string message;
            if (this._mediaClientWorking)
            {
                this._mediaClientWorking = false;
            }
            if (this._deviceClientWorking)
            {
                this._deviceClientWorking = false;
            }
            base.ReportOperationCompleted();
            this.SwitchToState(TestTool.GUI.Enums.ApplicationState.Idle);
            Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
            if (!string.IsNullOrEmpty(stage))
            {
                message = string.Format("{0}{1}{2}", stage, Environment.NewLine, exc.Message);
            }
            else
            {
                message = exc.Message;
            }
            base.View.DisplayLog(message.Replace("\n", Environment.NewLine));
        }

        protected void OnMediaUriReceived(MediaUri uri, VideoEncoderConfiguration encoder, AudioEncoderConfiguration audio)
        {
            base.View.ShowVideo(uri, encoder, audio);
        }

        private void OnOperationCompleted()
        {
            if (this._mediaClientWorking)
            {
                this._mediaClientWorking = false;
            }
            if (this._deviceClientWorking)
            {
                this._deviceClientWorking = false;
            }
            base.ReportOperationCompleted();
        }

        private void OnOperationStarted()
        {
            base.ReportOperationStarted();
        }

        protected void OnProfilesReceived(TestTool.Proxies.Onvif.Profile[] profiles)
        {
            base.View.SetProfiles(profiles);
        }

        private void OnResponseReceived(string response)
        {
            base.View.DisplayLog(response);
        }

        private void OnServicesInfoReceived(Capabilities capabilities, Service[] services)
        {
            if (capabilities != null)
            {
                if (capabilities.Media != null)
                {
                    base.View.MediaAddress = capabilities.Media.XAddr;
                }
            }
            else if (services != null)
            {
                Service service = services.FindService("http://www.onvif.org/ver10/media/wsdl");
                base.View.MediaAddress = service.XAddr;
            }
        }

        protected void OnSourceConfigsReceived(VideoSourceConfiguration[] configs)
        {
            base.View.SetVideoSourceConfigs(configs);
        }

        protected void OnVideoEncoderConfigOptionsReceived(VideoEncoderConfigurationOptions options)
        {
            base.View.SetVideoEncoderConfigOptions(options);
        }

        protected void OnVideoEncoderConfigsReceived(VideoEncoderConfiguration[] configs)
        {
            base.View.SetVideoEncoderConfigs(configs);
        }

        public override void Stop()
        {
            if (this._deviceClientWorking)
            {
                this._deviceClient.Stop();
            }
            if (this._mediaClientWorking)
            {
                this._mediaClient.Stop();
            }
        }

        public override void UpdateContext()
        {
            MediaInfo info = new MediaInfo {
                ServiceAddress = base.View.MediaAddress
            };
            ContextController.UpdateMediaInfo(info);
        }

        public override void UpdateView()
        {
            base.View.EnableControls(base.CurrentState == TestTool.GUI.Enums.ApplicationState.Idle);
        }

        public override bool RequestPending
        {
            get
            {
                if (!this._deviceClientWorking)
                {
                    return this._mediaClientWorking;
                }
                return true;
            }
        }
    }
}

